package com.browsesoft.baseadapter;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

import com.browsesoft.Entity;
import com.browsesoft.EntityManager;
import com.browsesoft.ExtendElement;
import com.browsesoft.Tools;
import com.browsesoft.htmlcomponent.HTMLBasicComponent;
import com.browsesoft.htmlcomponent.HTMLTableModel;
import com.browsesoft.tools.XMLTool;

public class EntitySearchTableModel implements HTMLTableModel {
	/**
	 * 所有列名
	 */
	private Object[] names = null;

	/**
	 * 所有列的内容描述
	 */
	private Object[] contexts = null;

	/**
	 * 查询到的所有实体
	 */
	private Object[] entities = null;

	/**
	 * 要查询的实体类型
	 */
	private String[] entityTypes = null;

	/**
	 * 要查询的表类型
	 */
	private String[] tablenames = null;

	/**
	 * 实体类型应满足的条件
	 */
	private String condition = null;

	/**
	 * 得到列数
	 * 
	 * @return 列数
	 */
	public int getColumnCount() {
		return this.names.length;
	}

	/**
	 * 得到列的名称
	 * 
	 * @param index
	 *            列号
	 * @return 列的名称
	 */
	public String getColumnName(int index) {
		return (String) this.names[index];
	}

	/**
	 * 得到列的英文名
	 * 
	 * @param index
	 *            列号
	 * @return 列的英文名
	 */
	public String getColumnEname(int index) {
		return "";
	}

	public Object getDatas() {
		return null;
	}

	/**
	 * 得到行数
	 * 
	 * @return 行数
	 */
	public int getRowCount() {
		// 实体个数
		return this.entities.length;
	}

	/**
	 * 得到某列的操作类型
	 * 
	 * @return 类型
	 */
	public String getType(int col) {
		return "td";
	}

	/**
	 * 设置条件
	 */
	public void setCondition(String condition) {
	}

	/**
	 * 修改单元值
	 */
	public void modifyCellValue(Element td, Document doc, int row, int col) {
		// 从实体列表中得到当前实体
		Entity entity = (Entity) this.entities[row];
		// 得到本列内容描述
		String desc = (String) this.contexts[col];
		// 根据内容描述解析得到具体内容
		try {
			String context = this.getContextByDescription(desc, entity);
			// 把具体内容输出
			Text text = (Text) XMLTool.createTextNode(doc, context);
			ExtendElement.replaceElementContext(td, text);
		} catch (Exception e) {
			Text text = (Text) doc.createTextNode("");
			ExtendElement.replaceElementContext(td, text);
		}
	}

	/**
	 * 解析内容描述，得到实际内容
	 * 
	 * @param description
	 *            内容描述
	 * @param entity
	 *            要得内容得实体
	 * @return 实际内容
	 */
	private String getContextByDescription(String description, Entity entity)
			throws Exception {
		Iterator iter = Tools.stringToLinkedList(description, '.').iterator();
		// 对于每一层属性
		while (iter.hasNext()) {
			// 得到属性值
			String attrName = (String) iter.next();
			Object o = this.getAttribute(entity, attrName);
			// 如果是最后一层
			if (!iter.hasNext()) {
				// 返回对象结果
				return o.toString();
			}
			// 否则
			else {
				// 用得到的实体继续取属性
				entity = (Entity) o;
			}
		}
		return null;
	}

	/**
	 * 根据属性名得到实体属性
	 */
	private Object getAttribute(Entity entity, String attrName)
			throws Exception {
		// 根据属性名得到属性值
		Object attrValue = entity.getAttributes().get(attrName);
		// 如果属性值存在
		if (attrValue != null && !attrValue.equals("")) {
			// 返回属性值
			return attrValue;
		}
		// 转换属性名第一个字符为大写
		String temp = attrName.substring(0, 1).toUpperCase();
		attrName = temp + attrName.substring(1);
		// 得到方法名
		String methodName = "get" + attrName;
		Method method = entity.getClass().getMethod(methodName, new Class[0]);
		// 执行该方法得到属性
		Object o = method.invoke(entity, new Object[0]);
		return o;
	}

	/**
	 * 初始化model
	 */
	public void init(HttpServletRequest request) throws Exception {
	}

	/**
	 * 处理用户请求
	 * 
	 * @param request
	 *            客户端请求
	 */
	public void service(HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		try {
			// 条件
			String condition = this.getConditionWithParam(this.condition,
					request);
			// 如果条件不为空
			if (condition != null && !condition.equals("")) {
				// 根据条件加载实体
				this.entities = this.loadEntities(condition);
			}
			// 否则
			else {
				this.entities = this.loadEntities("");
			}
		} catch (NullConditionException e) {
			this.entities = new Object[0];
		}
	}

	/**
	 * //根据条件加载实体
	 * 
	 * @param condition
	 * @return
	 */
	private Object[] loadEntities(String condition) {
		if (!this.tablenames[0].equals("") && this.tablenames.length != 0) {
			// 根据表名和条件装载实体
			return this.loadEntitiesByTablename(condition);
		}
		// 否则
		else {
			// 根据实体类型和条件装载实体
			return this.loadEntitiesByEntityType(condition);
		}
	}

	/**
	 * 根据实体类型及条件加载实体
	 */
	private Object[] loadEntitiesByEntityType(String condition) {
		Collection result = new LinkedList();
		// 对于实体类型列表中的每一类实体
		for (int i = 0; i < this.entityTypes.length; i++) {
			// 根据条件加载该实体
			result.addAll(EntityManager.getInstance().getEntities(
					this.entityTypes[i], condition));
		}
		return result.toArray();
	}

	/**
	 * 根据表名及条件加载实体
	 */
	private Object[] loadEntitiesByTablename(String condition) {
		Collection result = new LinkedList();
		// 对于表名列表中的每一个表
		for (int i = 0; i < this.tablenames.length; i++) {
			// 根据条件加载该实体
			result.addAll(EntityManager.getInstance().getEntitiesByTableName(
					this.tablenames[i], condition));
		}
		return result.toArray();
	}

	/**
	 * 把条件中的变量换成实际内容
	 * 
	 * @param condition
	 *            带参数的条件
	 * @param request
	 *            请求的参数
	 * @return 把参数替换成实际结果的条件
	 */
	private String getConditionWithParam(String condition,
			HttpServletRequest request) throws NullConditionException {
		String result = new String(condition);
		// 对于每一个参数
		int start = condition.indexOf("#");
		// 如果有参数
		while (start != -1) {
			// 得到参数名
			int end = condition.indexOf("#", start + 1);
			String paramName = condition.substring(start + 1, end);
			// 从请求中得到条件
			String paramValue = (String) request.getParameter(paramName);
			// 如果某个条件为空
			if (paramValue == null || paramValue.equals("")) {
				throw new NullConditionException();
			}
			result = result.replaceAll("#" + paramName + "#", "'" + paramValue
					+ "'");
			// 得到下一个
			start = condition.indexOf("#", end + 1);
		}
		return result;
	}

	/**
	 * 设置模型所对应的组件
	 * 
	 * @param component
	 *            对应的组件
	 */
	public void setComponent(HTMLBasicComponent component) {
		// 得到组件对应的元素
		Element e = component.getElement();
		// 从元素中得到对应列名
		this.names = this.getNames(e);
		// 从元素中得到各列的内容描述
		this.contexts = this.getContexts(e);
		// 从组件描述中得到实体类型,表名以及条件
		this.entityTypes = e.getAttribute("entities").split(",");
		this.tablenames = e.getAttribute("tablenames").split(",");
		this.condition = e.getAttribute("condition");
	}

	/**
	 * 根据组件所对应的元素得到所有列名
	 * 
	 * @param element
	 *            组件所对应的元素
	 * @return 所有列名数组
	 */
	private Object[] getNames(Element element) {
		Collection result = new LinkedList();
		// 得到表头行
		Element tr = (Element) ExtendElement.findElements(element, "type",
				"head").iterator().next();
		tr = (Element) tr.getElementsByTagName("template").item(0);
		// 对于表头的每一列
		NodeList nl = tr.getElementsByTagName("td");
		for (int i = 0; i < nl.getLength(); i++) {
			Element item = (Element) nl.item(i);
			// 得到列的显示内容，即表头名称
			Text text = (Text) ExtendElement.findElementContext(item)
					.iterator().next();
			// 添加到结果中
			result.add(text.getData());
		}
		return result.toArray();
	}

	/**
	 * 根据组件所对应的元素得到所有列的内容描述
	 * 
	 * @param element
	 *            组件所对应的元素
	 * @return 所有列的内容描述数组
	 */
	private Object[] getContexts(Element element) {
		Collection result = new LinkedList();
		// 得到表体行
		Element tr = (Element) ExtendElement
				.findElements(element, "type", "tr").iterator().next();
		tr = (Element) tr.getElementsByTagName("template").item(0);
		// 对于表体的每一列
		NodeList nl = tr.getElementsByTagName("td");
		for (int i = 0; i < nl.getLength(); i++) {
			Element item = (Element) nl.item(i);
			// 得到列的内容描述,添加到结果中
			result.add(item.getAttribute("context"));
		}
		return result.toArray();
	}

	/**
	 * 由Component决定需要Model处理的元素内容，在Component的updateElement()方法中调用
	 */
	public void updatePageElement(HTMLBasicComponent c) throws Exception {
	}
}